home *** CD-ROM | disk | FTP | other *** search
/ Skunkware 5 / Skunkware 5.iso / src / X11 / xpaint-2.1.1 / image.c < prev    next >
C/C++ Source or Header  |  1995-05-03  |  18KB  |  752 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. #include <X11/Intrinsic.h>
  16. #include "image.h"
  17. #include "hash.h"
  18. #include "palette.h"
  19. #include "misc.h"
  20.  
  21. #define HASH_SIZE    128
  22.  
  23. /*
  24. **  Faster macros for "fast" Image <-> XImage loops
  25. */
  26.  
  27. #define ZINDEX(x, y, img) (((y) * img->bytes_per_line) + \
  28.                (((x) * img->bits_per_pixel) >> 3))
  29.  
  30. #define ZINDEX32(x, y, img) ((y) * img->bytes_per_line) + ((x) << 2)
  31. #define ZINDEX8(x, y, img)  ((y) * img->bytes_per_line) + (x)
  32. #define ZINDEX1(x, y, img)  ((y) * img->bytes_per_line) + ((x) >> 3)
  33.  
  34. static void imageToPixmapLoop(Display*, Image*, Palette*, XImage*, Pixmap*);
  35.  
  36. /*
  37.  * The functions below are written from X11R5 MIT's code (XImUtil.c)
  38.  *
  39.  * The idea is to have faster functions than the standard XGetPixel function
  40.  * to scan the image data. Indeed we can speed up things by suppressing tests
  41.  * performed for each pixel. We do exactly the same tests but at the image
  42.  * level. Assuming that we use only ZPixmap images.
  43.  */
  44.  
  45. static unsigned long low_bits_table[] = {
  46.     0x00000000, 0x00000001, 0x00000003, 0x00000007,
  47.     0x0000000f, 0x0000001f, 0x0000003f, 0x0000007f,
  48.     0x000000ff, 0x000001ff, 0x000003ff, 0x000007ff,
  49.     0x00000fff, 0x00001fff, 0x00003fff, 0x00007fff,
  50.     0x0000ffff, 0x0001ffff, 0x0003ffff, 0x0007ffff,
  51.     0x000fffff, 0x001fffff, 0x003fffff, 0x007fffff,
  52.     0x00ffffff, 0x01ffffff, 0x03ffffff, 0x07ffffff,
  53.     0x0fffffff, 0x1fffffff, 0x3fffffff, 0x7fffffff,
  54.     0xffffffff
  55. };
  56.  
  57. /*
  58. **  Actuall Image routines
  59. **
  60. **
  61. */
  62.  
  63.  
  64. Image *ImageNew(int width, int height)
  65. {
  66.     Image    *image = XtNew(Image);
  67.  
  68.     image->refCount = 1;
  69.     image->isBW = False;
  70.     image->isGrey = False;
  71.     image->cmapPacked = False;
  72.     image->cmapSize = 0;
  73.     image->cmapData = NULL;
  74.     image->width = width;
  75.     image->height = height;
  76.     image->sourceColormap = None;
  77.     image->sourcePixmap = None;
  78.     image->sourceMask = None;
  79.     image->scale = 3;
  80.     if (width == 0 || height == 0)
  81.         image->data = NULL;
  82.     else
  83.         image->data = (unsigned char *)XtMalloc(width * height * sizeof(char) * 3);
  84.     image->maskData = NULL;
  85.     return image;
  86. }
  87.  
  88. Image *ImageNewCmap(int width, int height, int size)
  89. {
  90.     Image    *image = ImageNew(0, 0);
  91.  
  92.     if (size == 0)
  93.         image->scale = 3;
  94.     else if (size <= 256)
  95.         image->scale = 1;
  96.     else
  97.         image->scale = sizeof(short) / sizeof(char);
  98.  
  99.     image->width    = width;
  100.     image->height   = height;
  101.     image->data     = (unsigned char *)XtMalloc(width * height * sizeof(char) * image->scale);
  102.     if (size != 0)
  103.         image->cmapData = (unsigned char *)XtMalloc(size * sizeof(char) * 3);
  104.     image->cmapSize = size;
  105.  
  106.     return image;
  107. }
  108.  
  109. Image *ImageNewBW(int width, int height)
  110. {
  111.     Image    *image = ImageNewCmap(width, height, 2);
  112.  
  113.     image->cmapData[0] = 0;
  114.     image->cmapData[1] = 0;
  115.     image->cmapData[2] = 0;
  116.     image->cmapData[3] = 255;
  117.     image->cmapData[4] = 255;
  118.     image->cmapData[5] = 255;
  119.  
  120.     return image;
  121. }
  122.  
  123. Image *ImageNewGrey(int width, int height)
  124. {
  125.     int    i;
  126.     Image    *image = ImageNewCmap(width, height, 256);
  127.  
  128.     image->isGrey = True;
  129.     for (i = 0; i < image->cmapSize; i++) {
  130.         image->cmapData[i * 3 + 0] = i;
  131.         image->cmapData[i * 3 + 1] = i;
  132.         image->cmapData[i * 3 + 2] = i;
  133.     }
  134.  
  135.     return image;
  136. }
  137.  
  138. void ImageMakeMask(Image *image)
  139. {
  140.     image->maskData = (unsigned char *)XtMalloc(image->width * image->height * sizeof(char));
  141. }
  142.  
  143.  
  144. void ImageDelete(Image *image)
  145. {
  146.     image->refCount--;
  147.     if (image->refCount > 0)
  148.         return;
  149.  
  150.     if (image->cmapSize > 0 && image->cmapData != NULL)
  151.         XtFree((XtPointer)image->cmapData);
  152.     if (image->data != NULL)
  153.         XtFree((XtPointer)image->data);
  154.     if (image->maskData != NULL)
  155.         XtFree((XtPointer)image->maskData);
  156.     XtFree((XtPointer)image);
  157. }
  158.  
  159. /*
  160. **  Convert a colormap image into a RGB image
  161. **    useful for writers which only deal with RGB and not
  162. **    colormaps
  163. */
  164. Image *ImageToRGB(Image *image)
  165. {
  166.     unsigned char    *ip, *op;
  167.     Image    *out;
  168.     int    x, y;
  169.  
  170.     if (image->cmapSize == 0) {
  171.         image->refCount++;
  172.         return image;
  173.     }
  174.      
  175.     out = ImageNew(image->width, image->height);
  176.     op = image->data;
  177.  
  178.     for (y = 0; y < image->height; y++) { 
  179.         for (x = 0; x < image->width; x++) { 
  180.             ip = ImagePixel(image, x, y);
  181.             *op++ = *ip++;
  182.             *op++ = *ip++;
  183.             *op++ = *ip++;
  184.         }
  185.     }
  186.  
  187.     out->isBW   = image->isBW;
  188.     out->isGrey = False;
  189.     out->width  = image->width;
  190.     out->height = image->height;
  191.  
  192.     image->cmapPacked = False;
  193.  
  194.     return out;
  195. }
  196.  
  197. /*
  198. **  Create a nice image for writing routines.
  199. */
  200.  
  201. static int  writeCMP(XColor *a, XColor *b)
  202. {
  203.     return a->pixel - b->pixel;
  204. }
  205.  
  206. Image *PixmapToImage(Widget w, Pixmap pix, Colormap cmap)
  207. {
  208.     XImage        *xim;
  209.     Image        *image;
  210.     Display        *dpy = XtDisplay(w);
  211.         int             x, y;
  212.         int            width, height;
  213.     unsigned char    *ptr, *data;
  214.     unsigned short    *sptr;
  215.     int        format = 0;
  216.     void        *htable = NULL;
  217.     Palette        *map = PaletteFind(w, cmap);
  218.     Boolean        is8;
  219.     unsigned long    lbt;
  220.  
  221.     GetPixmapWHD(dpy, pix, &width, &height, NULL);
  222.     xim = XGetImage(dpy, pix, 0, 0, width, height, AllPlanes, ZPixmap);
  223.  
  224.     if (map == NULL)
  225.         map = PaletteGetDefault(w);
  226.  
  227.     if (map->isMapped) {
  228.         unsigned char    *cptr;
  229.  
  230.         image = ImageNewCmap(width, height, map->ncolors);
  231.         cptr = image->cmapData;
  232.  
  233.         for (y = 0; y < map->ncolors; y++, cptr += 3) {
  234.             XColor    *col = PaletteLookup(map, y);
  235.             unsigned char    r = col->red >> 8;
  236.             unsigned char    g = col->green >> 8;
  237.             unsigned char    b = col->blue >> 8;
  238.  
  239.             cptr[0] = r;
  240.             cptr[1] = g;
  241.             cptr[2] = b;
  242.         }
  243.     } else {
  244.         image = ImageNew(width, height);
  245.     }
  246.  
  247.     ptr   = image->data;
  248.     sptr  = (unsigned short *)image->data;
  249.     data  = xim->data;
  250.     lbt   = low_bits_table[xim->depth];
  251.  
  252.     for (y = 0; y < height; y++) {
  253.         for (x = 0; x < width; x++) {
  254.             XColor        c, *col;
  255.             Pixel        pixel;
  256.             unsigned char    r, g, b;
  257.  
  258.             if (xim->bits_per_pixel == 8) 
  259.                 pixel = data[ZINDEX8(x, y, xim)] & lbt;
  260.             else
  261.                 pixel = XGetPixel(xim, x, y);
  262.  
  263.             if (map->isMapped) {
  264.                 if (map->ncolors <= 256)
  265.                     *ptr++  = pixel;
  266.                 else
  267.                     *sptr++ = pixel;
  268.                 
  269.                 r = image->cmapData[pixel*3+0];
  270.                 g = image->cmapData[pixel*3+1];
  271.                 b = image->cmapData[pixel*3+2];
  272.             } else {
  273.                 col = PaletteLookup(map, pixel);
  274.  
  275.                 *ptr++ = r = col->red >> 8;
  276.                 *ptr++ = g = col->green >> 8;
  277.                 *ptr++ = b = col->blue >> 8;
  278.             }
  279.  
  280.             if (r != g || g != b)
  281.                 format = 2;
  282.             else if (format == 0 && r != 0 && r != 255)
  283.                 format = 1;
  284.         }
  285.  
  286.         if (y % 64 == 0)
  287.             StateTimeStep();
  288.     }
  289.  
  290.     /*
  291.     **  Check to see if we just created a B&W or Grey scale image?
  292.     */
  293.     if (format == 0 || format == 1) {
  294.         int        newSize;
  295.         unsigned char    *newMap;
  296.         unsigned char    *ip;
  297.         int        inc, v;
  298.  
  299.         if (format == 0) {
  300.             newSize = 2;
  301.             newMap = (unsigned char *)XtCalloc(sizeof(char) * 3, 2);
  302.             newMap[0+0] = 0;
  303.             newMap[0+1] = 0;
  304.             newMap[0+2] = 0;
  305.             newMap[3+0] = 255;
  306.             newMap[3+1] = 255;
  307.             newMap[3+2] = 255;
  308.         } else {
  309.             newSize = 256;
  310.             newMap = (unsigned char *)XtCalloc(sizeof(char) * 3, 256);
  311.             for (y = 0; y < 256; y++) {
  312.                 newMap[y * 3 + 0] = y;
  313.                 newMap[y * 3 + 1] = y;
  314.                 newMap[y * 3 + 2] = y;
  315.             }
  316.         }
  317.  
  318.         ip = image->data;
  319.         for (y = 0; y < height; y++) {
  320.             for (x = 0; x < width; x++, ip++) {
  321.                 unsigned char    *rgb;
  322.  
  323.                 rgb = ImagePixel(image, x, y);
  324.  
  325.                 if (format == 0 && *rgb == 255) {
  326.                     *ip = 1;
  327.                 } else {
  328.                     *ip = *rgb;
  329.                 }
  330.             }
  331.         }
  332.  
  333.         if (image->cmapData != NULL)
  334.             XtFree((XtPointer)image->cmapData);
  335.  
  336.         image->cmapSize = newSize;
  337.         image->cmapData = newMap;
  338.  
  339.         if (format == 0)
  340.             image->isBW = True;
  341.         else if (format == 1)
  342.             image->isGrey = True;
  343.     }
  344.  
  345.     image->sourceColormap = (unsigned long)cmap;
  346.     image->sourcePixmap   = (unsigned long)pix;
  347.  
  348.     if (htable != NULL)
  349.         HashDestroy(htable);
  350.     XDestroyImage(xim);
  351.  
  352.     return image;
  353. }
  354.  
  355. void PixmapToImageMask(Widget w, Image *image, Pixmap mask)
  356. {
  357.     XImage        *xim;
  358.     int        width, height;
  359.     int        x, y, endX, endY;
  360.     unsigned char    *ip;
  361.     Display        *dpy = XtDisplay(w);
  362.  
  363.     image->sourceMask = mask;
  364.     GetPixmapWHD(dpy, mask, &width, &height, NULL);
  365.     xim = XGetImage(dpy, mask, 0, 0, width, height, AllPlanes, ZPixmap);
  366.  
  367.     ImageMakeMask(image);
  368.     ip = image->maskData;
  369.  
  370.     if ((endX = image->width) > width)
  371.         endX = width;
  372.     if ((endY = image->height) > height)
  373.         endY = height;
  374.  
  375.     for (y = 0; y < endY; y++) {
  376.         for (x = 0; x < endX; x++) 
  377.             *ip++ = (Boolean)XGetPixel(xim, x, y);
  378.         for (;x < image->width; x++) 
  379.             *ip++ = True;
  380.     }
  381.     XDestroyImage(xim);
  382. }
  383.  
  384. /*
  385. **  Compress an image into a nice number of
  386. **   colors for display purposes.
  387. */
  388. static Image *quantizeColormap(Image *input, Palette *map, Boolean flag)
  389. {
  390.     Image        *output;
  391.     unsigned char    *op;
  392.     int        x, y;
  393.     int        ncol;
  394.  
  395.     /*
  396.     **  If the output is either B&W or grey do something
  397.     **   fast an easy.
  398.     */
  399.     if (!map->isGrey) 
  400.         return ImageCompress(input, map->ncolors);
  401.     
  402.     ncol = map->ncolors > 256 ? 256 : map->ncolors;
  403.     output = ImageNewCmap(input->width, input->height, ncol); 
  404.  
  405.     op = output->data;
  406.  
  407.     for (y = 0; y < ncol; y++) {
  408.         unsigned char    v = ((float)y / (float)(ncol-1)) * 255.0;
  409.         ImageSetCmap(output, y, v, v, v);
  410.     }
  411.  
  412.     for (y = 0; y < input->height; y++) {
  413.         for (x = 0; x < input->width; x++, op++) {
  414.             unsigned char    *dp, v;
  415.  
  416.             dp = ImagePixel(input, x, y);
  417.             v = (dp[0]*11 + dp[1]*16 + dp[2]*5) >> 5;  /* pp=.33R+.5G+.17B */
  418.             *op = (int)(((float)v / 256.0) * (float)ncol);
  419.         }
  420.     }
  421.  
  422.     output->maskData = input->maskData;
  423.     input->maskData  = NULL;
  424.     ImageDelete(input);
  425.     return output;
  426. }
  427.  
  428. static void compressColormap(Image *image)
  429. {
  430.     unsigned char    used[32768];
  431.     int        size = image->width * image->height;
  432.     int        i, count, newSize;
  433.     unsigned char    *newMap;
  434.     unsigned short    *isp;
  435.     unsigned char    *icp;
  436.  
  437.     if (image->cmapSize <= 2 || image->cmapPacked)
  438.         return;
  439.  
  440.     memset(used, False, sizeof(used));
  441.     
  442.     /*
  443.     **  Find out usage information over the colormap 
  444.     */
  445.     count = 0;
  446.     if (image->cmapSize > 256) {
  447.         isp = (unsigned short *)image->data;
  448.         for (i = 0; i < size && count != image->cmapSize; i++, isp++) {
  449.             if (!used[*isp]) {
  450.                 used[*isp] = True;
  451.                 count++;
  452.             }
  453.         }
  454.     } else {
  455.         icp = image->data;
  456.         for (i = 0; i < size && count != image->cmapSize; i++, icp++) {
  457.             if (!used[*icp]) {
  458.                 used[*icp] = True;
  459.                 count++;
  460.             }
  461.         }
  462.     }
  463.  
  464.     /*
  465.     **  Colormap is fully used.
  466.     */
  467.     if (count == image->cmapSize) {
  468.         image->cmapPacked = True;
  469.         return;
  470.     }
  471.  
  472.     /*
  473.     **  Now build the remapping colormap, and
  474.     **    set the index.
  475.     */
  476.     newSize = count;
  477.     newMap = (unsigned char *)XtCalloc(count, sizeof(unsigned char) * 3);
  478.     for (count = i = 0; i < image->cmapSize; i++) {
  479.         if (!used[i])
  480.             continue;
  481.         newMap[count * 3 + 0] = image->cmapData[i * 3 + 0];
  482.         newMap[count * 3 + 1] = image->cmapData[i * 3 + 1];
  483.         newMap[count * 3 + 2] = image->cmapData[i * 3 + 2];
  484.         used[i] = count++;
  485.     }
  486.  
  487.     if (image->cmapSize > 256 && newSize > 256) {
  488.         isp = (unsigned short *)image->data;
  489.         for (i = 0; i < size; i++, isp++)
  490.             *isp = used[*isp];
  491.     } else if (image->cmapSize > 256 && newSize <= 256) {
  492.         /*
  493.         **  Map a big colormap down to a small one.
  494.         */
  495.         isp = (unsigned short *)image->data;
  496.         icp = image->data;
  497.         for (i = 0; i < size; i++, icp++, isp++)
  498.             *icp = used[*isp];
  499.  
  500.         image->data = (unsigned char *)XtRealloc((XtPointer)image->data, size * sizeof(unsigned char));
  501.     } else {
  502.         icp = image->data;
  503.         for (i = 0; i < size; i++, icp++)
  504.             *icp = used[*icp];
  505.     }
  506.  
  507.     XtFree((XtPointer)image->cmapData);
  508.     image->cmapData = newMap;
  509.     image->cmapSize = newSize;
  510.     image->cmapPacked = True;
  511.     image->isGrey = False;
  512. }
  513.  
  514. /*
  515. **  Convert an imput image into a nice pixmap 
  516. **   so we can edit it.
  517. **
  518. **  Side effect  -- always destroy the input image
  519. */
  520. Boolean ImageToPixmap(Image *image, Widget w, Pixmap *pix, Colormap *cmap)
  521. {
  522.     GC        gc;
  523.     Display        *dpy = XtDisplay(w);
  524.     Palette         *map;
  525.     XImage        *xim;
  526.     int        x, y;
  527.     int        width = image->width, height = image->height;
  528.  
  529.     map   = PaletteCreate(w);
  530.     *cmap = map->cmap;
  531.  
  532.         if ((*pix = XCreatePixmap(dpy, DefaultRootWindow(dpy), image->width, image->height, map->depth)) == None)
  533.         return False;
  534.  
  535.     if ((xim = NewXImage(dpy, NULL, map->depth, image->width, image->height)) == NULL) {
  536.         XFreePixmap(dpy, *pix);
  537.         return False;
  538.     }
  539.  
  540.     if ((image->cmapSize > map->ncolors) ||
  541.         (image->cmapSize == 0 && map->isMapped))
  542.         image = quantizeColormap(image, map, False);
  543.  
  544.     if (image->cmapSize > 0)
  545.         compressColormap(image);
  546.  
  547.     imageToPixmapLoop(dpy, image, map, xim, pix);
  548.  
  549.     return True;
  550. }
  551.  
  552. Pixmap    MaskDataToPixmap(Widget w, int width, int height, 
  553.                 char *data, XRectangle *rect)
  554. {
  555.     Display        *dpy = XtDisplay(w);
  556.     GC        gc;
  557.     Pixmap        mask;
  558.     XImage        *xim;
  559.     int        x, y;
  560.     int        xs, ys;
  561.     unsigned char    *ucp;
  562.     int        pWidth, pHeight;
  563.  
  564.     if (data == NULL)
  565.         return None;
  566.  
  567.     if (rect == NULL) {
  568.         xs = 0;
  569.         ys = 0;
  570.         pWidth  = width;
  571.         pHeight = height;
  572.     } else {
  573.         xs = rect->x;
  574.         ys = rect->y;
  575.         pWidth  = rect->width;
  576.         pHeight = rect->height;
  577.     }
  578.  
  579.     mask = XCreatePixmap(dpy, DefaultRootWindow(dpy), pWidth, pHeight, 1);
  580.     gc   = XCreateGC(dpy, mask, 0, 0);
  581.     xim  = NewXImage(dpy, NULL, 1, pWidth, pHeight);
  582.  
  583.     if (xim->byte_order != xim->bitmap_bit_order) {
  584.         for (y = 0; y < pHeight; y++) {
  585.             ucp = data + (width * (y + ys)) + xs;
  586.             for (x = 0; x < pWidth; x++, ucp++)
  587.                 XPutPixel(xim, x, y, *ucp);
  588.         }
  589.     } else {
  590.         unsigned char    *op = xim->data;
  591.         unsigned char    *cp;
  592.  
  593.         if (xim->bitmap_bit_order == MSBFirst) {
  594.             for (y = 0; y < pHeight; y++) {
  595.                 ucp = data + (width * (y + ys)) + xs;
  596.                 for (x = 0; x < pWidth; x++, ucp++) {
  597.                     unsigned char    v = 0x80 >> (x & 7);
  598.  
  599.                     cp = &op[ZINDEX1(x, y, xim)];
  600.                     if (*ucp)
  601.                         *cp |= v;
  602.                     else
  603.                         *cp &= ~v;
  604.                 }
  605.             }
  606.         } else {
  607.             for (y = 0; y < pHeight; y++) {
  608.                 ucp = data + (width * (y + ys)) + xs;
  609.                 for (x = 0; x < pWidth; x++, ucp++) {
  610.                     unsigned char    v = 0x01 << (x & 7);
  611.  
  612.                     cp = &op[ZINDEX1(x, y, xim)];
  613.                     if (*ucp)
  614.                         *cp |= v;
  615.                     else
  616.                         *cp &= ~v;
  617.                 }
  618.             }
  619.         }
  620.         
  621.     }
  622.  
  623.     XPutImage(dpy, mask, gc, xim, 0, 0, 0, 0, pWidth, pHeight);
  624.     XFreeGC(dpy, gc);
  625.  
  626.     XDestroyImage(xim);
  627.  
  628.     return mask;
  629. }
  630.  
  631. Pixmap    ImageMaskToPixmap(Widget w, Image *image)
  632. {
  633.     return MaskDataToPixmap(w, image->width,
  634.                 image->height, image->maskData, NULL);
  635. }
  636.  
  637. /*
  638. **  Convert an imput image into a nice pixmap 
  639. **   so we can edit it.
  640. **
  641. **  Side effect  -- always destroy the input image
  642. */
  643. static void imageToPixmapLoop(Display *dpy, Image *image, Palette *map, XImage *xim, Pixmap *pix)
  644. {
  645.     GC        gc;
  646.     int        x, y;
  647.     int        width = image->width, height = image->height;
  648.  
  649.     if (image->cmapSize > 0) {
  650.         unsigned short     *sdp = (unsigned short *)image->data;
  651.         unsigned char     *cdp = (unsigned char  *)image->data;
  652.         Pixel        *list = (Pixel*)XtCalloc(sizeof(Pixel), image->cmapSize);
  653.         XColor        *xcol = (XColor*)XtCalloc(sizeof(XColor), image->cmapSize);
  654.  
  655.         for (y = 0; y < image->cmapSize; y++) {
  656.             xcol[y].red   = image->cmapData[y * 3 + 0] << 8;
  657.             xcol[y].green = image->cmapData[y * 3 + 1] << 8;
  658.             xcol[y].blue  = image->cmapData[y * 3 + 2] << 8;
  659.         }
  660.  
  661.         PaletteAllocN(map, xcol, image->cmapSize, list);
  662.  
  663.         if (xim->bits_per_pixel == 8) {
  664.             unsigned char    *data = xim->data;
  665.  
  666.             for (y = 0; y < height; y++)
  667.                 for (x = 0; x < width; x++, sdp++, cdp++) 
  668.                     data[ZINDEX8(x, y, xim)] = list[image->cmapSize > 256 ? *sdp : *cdp];
  669.         } else {
  670.             /*
  671.             **  Slow loop
  672.             */
  673.             for (y = 0; y < height; y++) {
  674.                 for (x = 0; x < width; x++, sdp++, cdp++) 
  675.                     XPutPixel(xim, x, y, list[image->cmapSize > 256 ? *sdp : *cdp]);
  676.                 if (y % 256 == 0)
  677.                     StateTimeStep();
  678.             }
  679.         }
  680.         
  681.         XtFree((XtPointer)list);
  682.         XtFree((XtPointer)xcol);
  683.     } else {
  684.         int        step = 64 * 256 / width;
  685.         unsigned char    *cp = image->data;
  686.  
  687.         for (y = 0; y < height; y++) {
  688.             for (x = 0; x < width; x++) {
  689.                 XColor    c;
  690.                 Pixel    p;
  691.  
  692.                 c.red   = *cp++ << 8;
  693.                 c.green = *cp++ << 8;
  694.                 c.blue  = *cp++ << 8;
  695.  
  696.                 p = PaletteAlloc(map, &c);
  697.  
  698.                 if (xim->bits_per_pixel == 8)
  699.                     xim->data[ZINDEX8(x, y, xim)] = p;
  700.                 else
  701.                     XPutPixel(xim, x, y, p);
  702.             }
  703.  
  704.             if (y % step == 0)
  705.                 StateTimeStep();
  706.         }
  707.     }
  708.  
  709.     gc = XCreateGC(dpy, *pix, 0, 0);
  710.     XPutImage(dpy, *pix, gc, xim, 0, 0, 0, 0, width, height);
  711.     XFreeGC(dpy, gc);
  712.  
  713.     XDestroyImage(xim);
  714.  
  715.     ImageDelete(image);
  716. }
  717.  
  718. Boolean ImageToPixmapCmap(Image *image, Widget w, Pixmap *pix, Colormap cmap)
  719. {
  720.     GC        gc;
  721.     Display        *dpy = XtDisplay(w);
  722.     Palette         *map;
  723.     XImage        *xim;
  724.     int        x, y;
  725.     int        width = image->width, height = image->height;
  726.  
  727.     if ((map = PaletteFind(w, cmap)) == NULL)
  728.         map = PaletteGetDefault(w);
  729.  
  730.     if (*pix == None) {
  731.         if ((*pix = XCreatePixmap(dpy, RootWindowOfScreen(XtScreen(w)), image->width, image->height, map->depth)) == None)
  732.             return False;
  733.     }
  734.  
  735.     if ((xim = NewXImage(dpy, NULL, map->depth, image->width, image->height)) == NULL) {
  736.         XFreePixmap(dpy, *pix);
  737.         return False;
  738.     }
  739.  
  740.     if ((image->cmapSize > map->ncolors) ||
  741.         (image->cmapSize == 0 && map->isMapped))
  742.         image = quantizeColormap(image, map, False);
  743.  
  744.     if (image->cmapSize > 0)
  745.         compressColormap(image);
  746.  
  747.     imageToPixmapLoop(dpy, image, map, xim, pix);
  748.  
  749.     return True;
  750. }
  751.  
  752.